package com.zwps.biz.domain.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.zwps.biz.domain.converter.DeptConverter;
import com.zwps.biz.domain.service.DeptService;
import com.zwps.biz.domain.tool.TreeCodeTool;
import com.zwps.biz.api.model.dto.dept.AddDeptDTO;
import com.zwps.biz.api.model.dto.dept.SelectTreeDTO;
import com.zwps.biz.api.model.dto.dept.UpdateDeptDTO;
import com.zwps.biz.api.model.vo.dept.DeptTreeVO;
import com.zwps.biz.dal.db.dao.DeptDAO;
import com.zwps.biz.dal.db.dao.UserDAO;
import com.zwps.biz.dal.db.object.DeptDO;
import com.zwps.biz.dal.db.object.UserDO;
import com.zwps.common.api.model.vo.LoginInfoVO;
import com.zwps.common.api.model.vo.LoginUserDeptVO;
import com.zwps.common.core.context.LoginInfoContext;
import com.zwps.common.core.exception.UserActionException;
import com.zwps.common.core.service.CommonService;
import com.zwps.common.tool.tree.TreeTool;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;

@Slf4j
@Service
@AllArgsConstructor
public class DeptServiceImpl implements DeptService, CommonService {

    private DeptDAO deptDAO;

    private UserDAO userDAO;

    private LoginUserDeptVO getCurrentLoginUserDept() {
        LoginInfoVO loginInfo = LoginInfoContext.getLoginInfo();
        if (StrUtil.isEmpty(loginInfo.getUser().getDeptId())) {
            throw new UserActionException("当前用户未设置部门");
        }
        LoginUserDeptVO dept = loginInfo.getDept();
        if (dept == null) {
            throw new UserActionException("当前用户的部门不存在");
        }
        return dept;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addDept(AddDeptDTO dto) {
        LoginUserDeptVO loginedUserDept = getCurrentLoginUserDept();
        String parentTreeCode = null;
        if (StrUtil.isNotEmpty(dto.getParentId())) {
            DeptDO dept = deptDAO.selectById(dto.getParentId());
//            if (dept == null) {
//                throw new UserActionException("上级部门不存在或已被删除");
//            }
//            if (!dept.getTreeCode().startsWith(loginedUserDept.getTreeCode())) {
//                throw new UserActionException("不能选择非当前登录用户所属部门");
//            }
            parentTreeCode = dept.getTreeCode();
        } else {
            dto.setParentId(loginedUserDept.getId());
            parentTreeCode = loginedUserDept.getTreeCode();
        }
        DeptDO sortLastDept = findLastDept(dto.getParentId());

        String treeCode = TreeCodeTool.generateIncremental(parentTreeCode,
                sortLastDept == null ? null : sortLastDept.getTreeCode());

        DeptDO dept = DeptConverter.INSTANCE.toDeptDO(dto);
        dept.setTreeCode(treeCode);
        if (deptDAO.insert(dept) < 1) {
            throw new UserActionException("新增部门失败");
        }
    }

    /**
     * 获取指定部门下通过treeCode排序，返回最后一个部门
     * 
     * @Title: findLastDept
     * @Description:
     * @param parentId
     * @return DeptDO
     * @author lyh
     * @date 2023年5月22日 下午2:29:00
     */
    public DeptDO findLastDept(String parentId) {
        LambdaQueryWrapper<DeptDO> countDeptQuery = Wrappers.lambdaQuery(DeptDO.class);
        if (StrUtil.isEmpty(parentId)) {
            countDeptQuery.eq(DeptDO::getParentId, parentId);
            countDeptQuery.or().isNull(DeptDO::getParentId);
        } else {
            countDeptQuery.eq(DeptDO::getParentId, parentId);
        }
        countDeptQuery.last(" ORDER BY replace(tree_code,'" + TreeCodeTool.TREE_CODE_TAG + "', '')+0 desc limit 1");
        return deptDAO.selectOne(countDeptQuery);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteDepts(String ids) {

        List<String> idList = Arrays.asList(ids.split(","));

        LambdaQueryWrapper<DeptDO> deptQuery = Wrappers.lambdaQuery(DeptDO.class).in(DeptDO::getId, idList);
        LoginUserDeptVO loginedUserDept = getCurrentLoginUserDept();
        List<DeptDO> deleteDeptList = deptDAO.selectList(deptQuery);
        if (deleteDeptList.isEmpty()) {
            return;
        }
        for (DeptDO deptDO : deleteDeptList) {
            if (!deptDO.getTreeCode().startsWith(loginedUserDept.getTreeCode())) {
                throw new UserActionException("不能删除非当前登录用户所属部门");
            } else if (deptDO.getTreeCode().equals(loginedUserDept.getTreeCode())) {
                throw new UserActionException("不能删除当前登录用户所属部门");
            }
        }

        List<DeptDO> deptList = deptDAO.selectList(Wrappers.lambdaQuery(DeptDO.class).in(DeptDO::getParentId, idList));
        for (DeptDO deptDO : deptList) {
            throw new UserActionException(String.format("存在下级部门【%s】，请先删除下级部门", deptDO.getDeptName()));
        }

        int result = deptDAO.deleteBatchIds(Arrays.asList(ids.split(",")));
        if (result != idList.size()) {
            long deptNum = deptDAO.selectCount(Wrappers.lambdaQuery(DeptDO.class).in(DeptDO::getId, idList));
            if (deptNum > 0) {
                log.error("Delete depts id[{}] fail, select item {}, delete success {}", ids, idList.size(), result);
                throw new UserActionException("删除失败");
            }
        }
        userDAO.update(null,
                Wrappers.lambdaUpdate(UserDO.class).in(UserDO::getDeptId, idList).set(UserDO::getDeptId, ""));

    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateDept(String id, UpdateDeptDTO dto) {
        DeptDO selectdDept = deptDAO.selectById(id);
        if (selectdDept == null) {
            throw new UserActionException("当前修改的部门不存在");
        }

        LambdaUpdateWrapper<DeptDO> updateCurrentDept = Wrappers.lambdaUpdate(DeptDO.class);
        String treeCode = null;

        if (change(dto.getParentId(), selectdDept.getParentId())) {
            String parentTreeCode = "";
            LoginUserDeptVO loginedUserDept = getCurrentLoginUserDept();

            if (!"".equals(dto.getParentId())) {
                if (dto.getParentId().equals(selectdDept.getId())) {
                    throw new UserActionException("不能选择自己作为上级部门");
                }

                DeptDO selectdParentDept = deptDAO.selectById(dto.getParentId());
                if (selectdParentDept == null) {
                    throw new UserActionException("更新后的上级部门不存在");
                }

                if (!selectdParentDept.getTreeCode().startsWith(loginedUserDept.getTreeCode())) {
                    throw new UserActionException("不能选择非当前登录用户所属部门");
                }

                if (selectdParentDept.getTreeCode().startsWith(selectdDept.getTreeCode())) {
                    throw new UserActionException("不能选择子集部门作为上级部门");
                }

                parentTreeCode = selectdParentDept.getTreeCode();
            } else {
                dto.setParentId(loginedUserDept.getId());
                parentTreeCode = loginedUserDept.getTreeCode();
            }
            updateCurrentDept.set(DeptDO::getParentId, dto.getParentId());

            DeptDO sortLastDept = findLastDept(dto.getParentId());
            treeCode = TreeCodeTool.generateIncremental(parentTreeCode,
                    sortLastDept == null ? null : sortLastDept.getTreeCode());

            updateCurrentDept.set(DeptDO::getTreeCode, treeCode);

        }

        updateCurrentDept.set(change(dto.getDeptName(), selectdDept.getDeptName()), DeptDO::getDeptName,
                dto.getDeptName());

        updateCurrentDept.set(change(dto.getSort(), selectdDept.getSort()), DeptDO::getSort, dto.getSort());

        updateCurrentDept.set(change(dto.getRemark(), selectdDept.getRemark()), DeptDO::getRemark, dto.getRemark());

        if (StrUtil.isNotEmpty(updateCurrentDept.getSqlSet())) {
            updateCurrentDept.eq(DeptDO::getId, id);
            if (deptDAO.update(null, updateCurrentDept) < 1) {
                throw new UserActionException("修改部门信息失败");
            }
        }

        // 这里修改要在当前部门修改之后，如果当前部门的上级ID是置空，可能会出现treeCode违反唯一约束
        if (treeCode != null) {
            // 可能不存在子集，所以不作修改条数判断
            deptDAO.updateChildrenTreeCode(selectdDept.getTreeCode(), treeCode, TreeCodeTool.TREE_CODE_TAG);
        }
    }

    // 目前使用不上，实现也存在问题
//    @Override
//    public List<DeptDO> selectDepts(SelectDeptDTO dto) {
//        LambdaQueryWrapper<DeptDO> deptQuery = Wrappers.lambdaQuery(DeptDO.class);
//        String deptId = LoginInfoContext.getUser().getDeptId();
//        out.println(LoginInfoContext.getUser());
//        if (StrUtil.isNotEmpty(deptId)) {
//            DeptDO dept = deptDAO.selectById(deptId);
//            if (dept == null) {
//                throw new UserActionException("当前用户的部门不存在");
//            }
//            deptQuery.likeLeft(DeptDO::getTreeCode, dept.getTreeCode());
//        }
//        deptQuery.eq(StrUtil.isNotEmpty(dto.getParentId()), DeptDO::getParentId, dto.getParentId());
//        deptQuery.eq(StrUtil.isNotEmpty(dto.getTreeCode()), DeptDO::getTreeCode, dto.getTreeCode());
//        deptQuery.like(StrUtil.isNotEmpty(dto.getDeptName()), DeptDO::getDeptName, dto.getDeptName());
//        deptQuery.orderByAsc(DeptDO::getSort);
//        return deptDAO.selectList(deptQuery);
//    }

    @Override
    public List<DeptTreeVO> findDeptTree(SelectTreeDTO dto) {
        LambdaQueryWrapper<DeptDO> deptQuery = Wrappers.lambdaQuery(DeptDO.class);
        LoginUserDeptVO deptVO = LoginInfoContext.getLoginInfo().getDept();
        if (deptVO == null) {
            throw new UserActionException("当前用户的部门不存在");
        }
        deptQuery.likeRight(DeptDO::getTreeCode, deptVO.getTreeCode()).ne(DeptDO::getTreeCode, deptVO.getTreeCode());
        if (StrUtil.isNotEmpty(dto.getParentId())) {
            DeptDO dept = deptDAO.selectById(dto.getParentId());
            if (dept == null) {
                throw new UserActionException("查询指定的部门不存在");
            }
            deptQuery.and((a -> {
                a.eq(DeptDO::getParentId, dto.getParentId()).or().likeRight(DeptDO::getTreeCode, dept.getTreeCode());
            }));
        }
        deptQuery.like(StrUtil.isNotEmpty(dto.getDeptName()), DeptDO::getDeptName, dto.getDeptName());
        List<DeptDO> deptList = deptDAO.selectList(deptQuery);
        if (deptList.isEmpty()) {
            return CollUtil.newArrayList();
        }
        Function<DeptDO, DeptTreeVO> treeInstance = (a) -> {
            DeptTreeVO vo = DeptConverter.INSTANCE.toDeptTreeVO(a);
            if ("1".equals(dto.getCountUserNum())) {
                vo.setUserNum(deptDAO.countUserNum(a.getTreeCode()));
            }
            return vo;
        };
        return TreeTool.build(deptList, treeInstance, (a) -> a.getId(), (a) -> a.getParentId(), (a) -> a.getDeptName(),
                (a) -> a.getSort());
    }

    @Override
    public List<String> findDeptParentIds(String deptId) {
        LoginUserDeptVO dept = LoginInfoContext.getLoginInfo().getDept();
        if (dept == null) {
            throw new UserActionException("当前用户的部门不存在");
        }
        DeptDO deptDO = deptDAO.selectById(deptId);
        if (deptDO == null) {
            throw new UserActionException("查询指定的部门不存在");
        }
        if (!deptDO.getTreeCode().startsWith(dept.getTreeCode())) {
            throw new UserActionException("没有该部门操作权限：" + deptDO.getDeptName());
        }
        List<String> treeCodes = TreeCodeTool.splitTreeCodeAssembly(deptDO.getTreeCode(), dept.getTreeCode());
        if (treeCodes.isEmpty()) {
            treeCodes.add(deptId);
            return treeCodes;
        }
        return deptDAO.findDeptParentIds(treeCodes, TreeCodeTool.TREE_CODE_TAG);
    }

}
